<?php
class Model_ZendDb_NewsService implements Model_NewsService
{
    /**
     * @var Zend_Db_Adapter_Abstract
     */
    private $_db;
    
    /**
     * @var Model_ZendDb_DbTable_News
     */
    private $_news;
    
    /**
     * @var Model_ZendDb_DbTable_UserNews
     */
    private $_user_news;
    
    /**
     * @var Model_ZendDb_DbTable_Feed
     */
    private $_feed;
    
    public function __construct()
    {
        $this->_news = new Model_ZendDb_DbTable_News();
        $this->_user_news = new Model_ZendDb_DbTable_UserNews();
        $this->_feed = new Model_ZendDb_DbTable_Feed();
        
        $this->_db = $this->_news->getAdapter();
    }
    
    /**
     * Check if a news already exists
     * 
     * @param String $url
     * @return Model_Entity_News | null if no news where found  
     */
    private function isNewsPresent($url) {
    	$select = $this->_db->quoteInto('url = ?', $url);
        $result = $this->_news->fetchRow($select);
        
        $news = null;
        
        if ($result != null) {
        	$news = new Model_Entity_News($result->toArray());
        }
        
        return $news;
    }
    
    /**
     * Check if a user already has a news
     * 
     * @param Model_Entity_News $news
     * @return boolean
     */
    private function isNewsAlreadyOwned(Model_Entity_News $news) {
    	$select = $this->_user_news->select();
    	$select->where('user_oid = ?', $news->getOwners()->getOid());
    	$select->where('news_oid = ?', $news->getOid());
    	
    	$result = $this->_user_news->fetchAll($select);
    	
    	return (0 == count($result)) ? false : true;
    }
    
    /**
     * Set news as important 
     * 
     * @see application/models/Model_NewsService
     * @param Model_Entity_News $news
     * @return void
     * @throws Exception
     */
    public function setIsImportant(Model_Entity_News $news) {
        $data['isImportant'] = $news->getIsImportant();
        
        $this->_user_news->update($data,
                            array('news_oid = ?' => $news->getOid(), 
                                  'user_oid = ?' => $news->owners->oid));
    }

    /**
     * Set news unread
     * 
     * @param Model_Entity_News $news
     * @return void
     * @see application/models/Model_NewsService
     */
    public function setIsRead(Model_Entity_News $news) {
        $data['isRead'] = $news->getIsRead();
        
        $this->_user_news->update($data,
                            array('news_oid = ?' => $news->getOid(), 
                                  'user_oid = ?' => $news->owners->oid));
    }
    
    /**
     * Get all news for a given feed
     * 
     * @param $feed
     * @return array of Model_Entity_News
     * @see application/models/Model_NewsService#getNews($feed)
     */
    public function getNews(Model_Entity_Feed $feed) {
    	$select = $this->_news->select();
        $select->where('feed_oid = ?', $feed->oid)
               ->order(array('pubDate DESC'));
        $newsRowset = $this->_news->fetchAll($select);
        
        $result = array();
        foreach ($newsRowset as $newsRow) {
            $news = new Model_Entity_News($newsRow->toArray());
            $result[] = $news;
        }
        
        return $result;
    }
    
    /**
     * Get all user news for a given feed
     * 
     * @param Model_Entity_Feed $feed
     * @see application/models/Model_NewsService#getNews()
     * @return array of Model_Entity_News
     */
    public function getUserNews(Model_Entity_Feed $feed) {
    	$select = $this->_db->select();
    	
    	$select->from('news')
    	       ->join(array('un' => 'user_news'), 
    	              'un.news_oid = news.oid', 
    	              array('un.isRead','un.isImportant'))
    	       ->where('news.feed_oid = ?', $feed->getOid())
    	       ->where('un.user_oid = ?', $feed->getOwners()->getOid())
    	       ->where('un.isDeleted = 0')
               ->order(array('news.pubDate DESC'));
               
    	$newsRowset = $this->_db->fetchAll($select);
        
    	$result = array();
        foreach ($newsRowset as $newsRow) {
            $news = new Model_Entity_News($newsRow);
                    
            $result[] = $news;
        }
        
        return $result;
    }
    
    /**
     * Get unread user news count
     * 
     * @param int $feedID
     * @param int $userID
     * @return int
     * @see application/models/Model_NewsService#getUnreadNewsCount($feedID, $userID)
     */
    public function getUnreadNewsCount($feedID, $userID) {
    	$sql = "SELECT COUNT(*) AS elements FROM news ".
    	       "JOIN user_news AS un ON un.news_oid = news.oid ".
    	       "WHERE un.isDeleted = 0 AND un.isRead = 0 ".
    	       "AND news.feed_oid = ?  AND un.user_oid = ?";
    	
    	$result = $this->_db->fetchAll($sql, array($feedID, $userID));
    	    	
    	return $result[0]['elements'];
    }
    
    /**
     * Add a news
     * 
     * @param Model_Entity_News $news
     * @return int the id of the inserted news
     * @see application/models/Model_NewsService#addNews($news)
     */
    public function addNews(Model_Entity_News $news) {
    	$dupNews = $this->isNewsPresent($news->getUrl());
    	
    	if (null == $dupNews) {
    		$newsData =  $news->getOptions();
    		
    		unset($newsData['isRead']);
            unset($newsData['isImportant']);
            unset($newsData['owners']);
            unset($newsData['feed']);
            
            $newsData['feed_oid'] = $news->getFeed()->getOid();
            
            //If no pubDate is setted, assign to it the current timestamp
            $pubdate = $news->getPubDate();
            if (empty($pubdate)) {
            	$newsData['pubDate'] = date('Y-m-d H:i:s');
            }
            
            return $this->_news->insert($newsData);
    	} else {
    		return $dupNews->getOid();
    	}
    }
    
    /**
     * Add a user news
     * 
     * @param Model_Entity_News $news
     * @return void
     * @see application/models/Model_NewsService#addUserNews($news)
     */
    public function addUserNews(Model_Entity_News $news) {
    	if (!$this->isNewsAlreadyOwned($news)) {
    		
            $this->_user_news->insert(array(
                'news_oid' => $news->getOid(),
                'user_oid' => $news->getOwners()->getOid()
            ));
    	}
    }
    
    /**
     * Fetch all news marked as important by a user
     * 
     * @param int $userID
     * @return array of Model_Entity_News
     * @see application/models/Model_NewsService#getImportantNews($userID)
     */
    public function getImportantNews($userID) {
    	$sql = "SELECT news.*, un.isImportant, un.isRead FROM news ".
    	       "JOIN user_news AS un ON news.oid = un.news_oid ".
    	       "WHERE un.user_oid = ? AND un.isImportant = 1 AND un.isDeleted =0 " .
    	       "ORDER BY news.pubDate DESC";
    	
    	$resultSet = $this->_db->fetchAll($sql, array($userID));
    	
    	$news = array();
    	foreach ($resultSet as $row) {
    		$news[] = new Model_Entity_News($row);
    	}
    	
    	return $news;
    }
    
    /**
     * Mark as deleted a given user news
     * 
     * @param Model_Entity_News $news
     * @return void
     * @see application/models/Model_NewsService#deleteUserNews($news)
     */
    public function deleteUserNews(Model_Entity_News $news) {
    	$data['isDeleted'] = 1;
    	$this->_user_news->update($data,
    	                          array('user_oid = ?' => $news->owners->oid,
    	                                'news_oid = ?' => $news->oid));
    }
    
    /**
     * Search for news matching search criteria based on contents of 
     * title description and body 
     * 
     * @param array $criteria
     * @return array of Model_Entity_News
     * @see application/models/Model_NewsService#searchNews($criteria)
     */
    public function searchUserNews($criteria) {
    	$select = $this->_db->select();
    	
        $contains = '%'.$criteria['contains'].'%';
        
        $select->from('news')
               ->join(array('un' => 'user_news'), 
                      'un.news_oid = news.oid', 
                      array('un.isRead','un.isImportant'))
               ->where('un.user_oid = ?', $criteria['userID'])
               ->where('un.isDeleted = 0')
               ->where('UPPER(news.title) LIKE UPPER(?) OR '.
                       'UPPER(news.description) LIKE UPPER(?) OR '.
                       'UPPER(news.body) LIKE UPPER(?)', $contains)
               ->order(array('news.pubDate DESC'));
               
        $newsRowset = $this->_db->fetchAll($select);
        
        $result = array();
        foreach ($newsRowset as $newsRow) {
            $news = new Model_Entity_News($newsRow);
                    
            $result[] = $news;
        }
        
        return $result;
    }
}